from lxml import etree
from io import StringIO
'''
在 XPath中有多中节点关系分别是父节点、子节点、同胞节点、先辈节点、后代节点

在上面的例子中

父节点：每个元素以及属性都有一个父节点，如：div 节点的父节点是 body 节点
子节点：元素节点可有零个、一个或多个子节点，如：第一个 ul 节点的子节点是4个 li 节点
同胞节点：拥有相同的父节点的节点，如：两个 div 节点是同胞节点
先辈节点：某节点的父节点、父节点的父节点…，如：ul 节点的先辈节点有 div 节点、body 节点
后代节点：某个节点的子节点，子节点的子节点…，如：body 节点的后代节点有div 节点、ul 节点、li 节点

基本语法
表达式	描述
nodeName	选择nodeName节点的所有子节点
/	从根节点开始
//	从匹配的节点开始选择节点
.	选择当前节点
..	选择当前节点的父节点
@	选择元素
*	匹配任意元素节点
@*	匹配任意属性节点
用上面的 Html 文档举个例子

路径表达式	描述
body	选取 body 的所有子节点
/html	选取 html 节点
//div	选取所有 div 节点
//div/./h4	div 节点下的 h4 节点
../div	选取当前节点的父节点下的所有 div 节点
//@class	所有带有 class 元素的节点
//*	选择所有节点
//@*	选择所有属性节点
常用函数
表达式	描述
position()	返回节点的 index 位置
last()	返回节点的个数
contains(string1,string2)	string1 是否包含 string2
text()	返回文本节点
comment()	返回注释节点
normalize-space(string)	去除首位空格，中间多个空格用一个空格代替
substring(string,start,len)	返回从 start 位置开始的指定长度的子字符串,第一个字符下标为1
substring-before(string1,string2)	返回string1中位于第一个string2之前的部分
substring-after(string1,string2)	返回string1中位于第一个string2之后的部分
同样用上面的Html文档举个例子

路径表达式	描述
//div[position()>1]	选择第二个 div 节点
//div[last()]	选择最后一个 div 节点
contains(//h4[2],’手机’)	第二个 h4 标签是否包含手机字符串
//li/text()	li 节点中的文本内容
//div/comment()	div 节点下的 html 注释
normalize-space(//li[@class=’blank’])	li 节点下 class属性为 blank 的文本去掉空格
substring(//h4[1],1,2)	第一个 h4 节点的前2个字
substring-before(//h4[1],’品牌商’)	第一个 h4 节点的品牌商字符串之前的字符串
substring-after(//h4[1],’品牌商’)	第一个 h4 节点的品牌商字符串之后的字符串
谓语
XPath 中的谓语就是删选表达式，相当于 SQL 中的 Where 条件，谓语被嵌在 [ ] 中

路径表达式	描述
//div[1]	选择第一个 div 节点
//div[2]/ul/li[last()]	选择第二个 div 节点下的最后一个 li 节点
//div[2]/ul/li[position()>3]	选择第二个 div 节点下的前两个 li 节点
//ul[@class]	选择所有带 class 属性的 ul 节点
//ul[@class=’computer’]	选择 class 属性为 computer 的 ul 节点
//h4[span = 4]	选择 h4 节点下 span 值等于4的节点
'''
test_html = '''
<html>
    <body>
        <div>
            <!-- 这里是注释 -->
            <h4>手机品牌商<span style="margin-left:10px">4</span></h4>
            <ul>
               <li>小米</li>
               <li>华为</li>
               <li class='blank'> OPPO </li>
               <li>苹果</li>
            </ul>
        </div>
        <div>
            <h4>电脑品牌商<span style="margin-left:10px">3</span></h4>
            <ul class="ul" style="color:red">
                <li>戴尔</li>
                <li>机械革命</li>
                <li>ThinkPad</li>
            </ul>
        </div>
    </body>
</html>'''
'''
etree.parse() 函数可以解析一个网页文件还可以解析字符串， 在网页中下载的数据一般都是字符串形式的，使用 parse(StringIO(str)) 将整个页面内容解析加载构建一个 ElementTree 对象，ElementTree 可以使用 XPath 语法精准找到需要的数据
'''
html = etree.parse(StringIO(test_html))
# print(html)

# 获取所有 li 标签数据
# li_list = html.xpath('//li')
#
# print("类型：")
# print(type(li_list))
#
# print("值：")
# print(li_list)
#
# print("个数：")
# print(len(li_list))
# for l in li_list:
#     print("li文本为：" + l.text)
# 获取带 class=’blank’ 属性数据
# blank_li_list = html.xpath('//li[@class="blank"]')
# print("类型：")
# print(type(blank_li_list))
# print("值：")
# print(blank_li_list)
# print("个数：")
# print(len(blank_li_list))
# for l in blank_li_list:
#     print("li文本为：" + l.text)

# 属性操作
# ul = html.xpath('//ul')[1]
# #遍历属性
# for name, value in ul.attrib.items():
#     print('{0}="{1}"'.format(name, value))
#
# #添加新的属性
# ul.set("new_attr", "true")
# # 获取单个属性
# new_attr = ul.get('new_attr')
# print(new_attr)

# 获取最后一个div ul li 标签数据
# html = etree.HTML(test_html)
# last_div = html.xpath('//div[last()]/ul/li/text()')
# for i in last_div:
#     print(i)

# 添加子节点
# last_div = html.xpath('//div[last()]/ul/li/text()')
# child = etree.Element("child")
# child.text = "这里是新的子元素"
# last_div.append(child)
# 查询子节点
# print(last_div[3].text)

# 查找并设置第一个查询到的元素
first_ul = html.find("//ul")
ul_li = first_ul.xpath("li")
print(len(ul_li))
for li in ul_li:
    # 删除元素
    first_ul.remove(li)

ul_li = first_ul.xpath("li")
print(len(ul_li))
if len(ul_li) == 0:
    print("元素被删除了")


# 遍历元素后代
# body = html.find("body")
# for sub in body.iter():
#     print(sub.tag)
    # print(sub.text)

'''
工具
在 google 浏览器开发者模式下，Elements 界面选择元素后右键 Copy，可以 Copy 元素的 XPath 路径
XPath Helper 是一个 google 浏览器插件，可以验证 XPath 是否正确

学习了 XPAth 的知识，可以快速匹配单个或多个元素节点和属性，在工作中大大加快了工作的效率。
lxml 是一个 Python 中强大的 Xml 和 Html 处理模块，结合 XPath 的使用在程序中快速、便捷的分析、修改网页内容。
'''
